<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    function call (fn, obj, ...args) {
      console.log('call()')
      if (obj===undefined || obj===null) {
        // 直接执行调用call的函数
        return fn(...args)
        // obj = window
      }
      
      // 给obj添加一个临时方法, 方法对应的函数为fn
      obj.tempFn = fn
      // 通过obj执行这个临时方法, 得到执行结果
      const result = obj.tempFn(...args)   // 此时obj中有tempFn方法
      // 删除这个临时方法
      delete obj.tempFn
      // 返回方法的执行结果
      return result


      // const obj = {m: 1}
      // console.log(obj) //会输出此时对象内部的数据  (快照)
      // delete obj.m

    }

    function apply (fn, obj, args) {
      console.log('apply()')
      return call(fn, obj, ...args)
    }

    function bind (fn, obj, ...args) {
      // 修正obj
      if (obj===undefined || obj===null) {
        obj = window
      }

      // 返回一个新函数
      return function (...args2) {
        // 调用原函数fn, 并指定this为obj
        return call(fn, obj, ...args, ...args2) 
      }
    }
    
  </script>
  <script>
    function fn(a, b) {
      console.log(a, b, this)
      return a + b
    }
    const obj = {m: 1}
    // console.log(call(fn, obj, 2, 3))
    // console.log(call(fn, undefined, 3, 4))
    // console.log(call(fn, null, 3, 4))

    // console.log(apply(fn, obj, [2, 3]))
    // console.log(apply(fn, undefined, [3, 4]))
    // console.log(apply(fn, null, [3, 4]))

    bind(fn, obj)(1, 2)
    bind(fn, undefined)(1, 2)
    bind(fn, null)(1, 2)
    bind(fn, obj, 3)(1, 2)
    bind(fn, obj, 3, 4)(1, 2)

    const fn2 = bind(fn, obj, 3, 4)
    fn2()

  </script>
</body>
</html>